<?php
namespace App\Providers;

use App\Facades\EasyWechat;
use App\Models\WxMpList;
use App\Models\WxMpOpenAuthorizer;
use App\Services\WxCommon\WxError;
use App\Services\WxMp\WxMpPayListService;
use EasyWeChat\OfficialAccount\Application as OfficialAccount;
use EasyWeChat\MiniProgram\Application as MiniProgram;
use EasyWeChat\OpenPlatform\Application as OpenPlatform;
use EasyWeChat\Payment\Application as Payment;
use EasyWeChat\Work\Application as Work;
use Illuminate\Support\ServiceProvider;
use App\Services\WxMp\WxMpListService;

/**
 * EasyWechat服务提供者
 * 为了使easywechat支持后台配置不同微信应用，故添加此服务提供者
 * @package App\Providers
 */
class EasyWechatServiceProvider extends ServiceProvider
{
    /**
     * 指定是否延迟加载
     * @var bool
     */
    protected $defer = false;
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {

    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //注册服务号、小程序单例
        $wxMplistSer = new WxMpListService();
        $wechatList = $wxMplistSer->getValidMpList();
        $isUpdateCache = false;
        if (!empty($wechatList)){
            $typeConf = [
                WxMpListService::TYPE_WECHAT => 'official_account',
                WxMpListService::TYPE_APPLET => 'mini_program',
                WxMpListService::TYPE_OPEN_PLATFORM => 'open_platform',
            ];
            foreach ($wechatList as $config){
                $typeName = isset($typeConf[$config['type']]) ? $typeConf[$config['type']] : '';
                if (empty($typeName)){
                    continue;
                }
                $this->app->singleton("wechat.{$typeName}.{$config['appid']}", function ($laravelApp) use ($config, $typeName, &$isUpdateCache) {
                    //格式化配置
                    $formatConfig = [
                        'app_id' => $config['appid'] ?? '',
                        'secret' => $config['secret'] ?? '',
                        'token' => $config['token'] ?? '',
                        'aes_key' => $config['aes_key'] ?? '',
                        'log' => [
                            'default' => env('WECHAT_LOG_ENV', 'develop'), // 默认使用的 channel，生产环境可以改为下面的 production
                            'channels' => [
                                // 测试环境
                                'develop' => [
                                    'driver' => 'daily',
                                    'path' => storage_path('logs/wechat_'.$typeName.'_'.$config['appid'].'.log'),
                                    'level' => 'debug',
                                ],
                                // 生产环境
                                'production' => [
                                    'driver' => 'daily',
                                    'path' => storage_path('logs/wechat_'.$typeName.'_'.$config['appid'].'.log'),
                                    'level' => 'info',
                                ],
                            ],
                        ],
                    ];
                    if ($config['type'] == WxMpListService::TYPE_WECHAT){//服务号，用户授权认证回调地址
                        $formatConfig['oauth'] = [
                            'scopes'   => ['snsapi_userinfo','snsapi_base'],
                            'callback' => route('callback.wechat.oauth', ['appid'=>$config['appid']]),
                        ];
                        if ($config['is_from_open']){//判断公众号是否来源于开放平台
                            $openPlatform = EasyWechat::openPlatform($config['open_appid']);
                            $authorizerRefreshToken = $config['open_authorizer']['refresh_token'] ?? '';
                            if (empty($authorizerRefreshToken)){
                                $authorizerInfo = $openPlatform->getAuthorizer($config['appid']);
                                //校验错误
                                WxError::checkApiResponse($authorizerInfo);
                                $authorizerRefreshToken = $authorizerInfo['authorization_info']['authorizer_refresh_token'];
                                //更新至数据表
                                $wxOpenAuthorizerModel = WxMpOpenAuthorizer::where('appid', $config['appid'])->first();
                                if ($wxOpenAuthorizerModel){
                                    $wxOpenAuthorizerModel->refresh_token = $authorizerRefreshToken;
                                    $wxOpenAuthorizerModel->save();
                                }
                                //是否更新缓存
                                $isUpdateCache = true;
                            }
                            $app = $openPlatform->officialAccount($config['appid'], $authorizerRefreshToken);
                        }else{
                            $finalConfig = array_merge(config('wechat.defaults', []), ['http' => config('wechat.http', [])], $formatConfig);
                            $app = new OfficialAccount($finalConfig);
                        }
                    }elseif ($config['type'] == WxMpListService::TYPE_APPLET){//小程序
                        if ($config['is_from_open']){//判断公众号是否来源于开放平台
                            $openPlatform = EasyWechat::openPlatform($config['open_appid']);
                            $authorizerRefreshToken = $config['open_authorizer']['refresh_token'] ?? '';
                            if (empty($authorizerRefreshToken)){
                                $authorizerInfo = $openPlatform->getAuthorizer($config['appid']);
                                //校验错误
                                WxError::checkApiResponse($authorizerInfo);
                                $authorizerRefreshToken = $authorizerInfo['authorization_info']['authorizer_refresh_token'];
                                //更新至数据表
                                $wxOpenAuthorizerModel = WxMpOpenAuthorizer::where('appid', $config['appid'])->first();
                                if ($wxOpenAuthorizerModel){
                                    $wxOpenAuthorizerModel->refresh_token = $authorizerRefreshToken;
                                    $wxOpenAuthorizerModel->save();
                                }
                                //是否更新缓存
                                $isUpdateCache = true;
                            }
                            $app = $openPlatform->miniProgram($config['appid'], $authorizerRefreshToken);
                        }else {
                            $finalConfig = array_merge(config('wechat.defaults', []), ['http' => config('wechat.http', [])], $formatConfig);
                            $app = new MiniProgram($finalConfig);
                        }
                    }elseif ($config['type'] == WxMpListService::TYPE_OPEN_PLATFORM){//开放平台
                        $finalConfig = array_merge(config('wechat.defaults', []), ['http' => config('wechat.http', [])], $formatConfig);
                        $app = new OpenPlatform($finalConfig);
                    }
                    //是否使用laravel自带缓存
                    if (config('wechat.defaults.use_laravel_cache')) {
                        $app['cache'] = $laravelApp['cache.store'];
                    }
                    $app['request'] = $laravelApp['request'];
                    //开放平台自动恢复推送component_verify_ticket协议
                    if ($config['type'] == WxMpListService::TYPE_OPEN_PLATFORM){//开放平台
                        try{
                            $ticket = $app->verify_ticket->getTicket();
                        }catch (\Exception $e){
                            $ticket = '';
                        }
                        if (empty($ticket)){
                            $mpList = WxMpList::where('appid', $config['appid'])->first();
                            if ($mpList->open_verify_ticket){
                                $app->verify_ticket->setTicket($mpList->open_verify_ticket);
                            }
                        }
                    }

                    return $app;
                });
                if ($config['is_default']){
                    $this->app->alias("wechat.{$typeName}.".$config['appid'], 'wechat.'.$typeName);
                }
            }
        }
        $isUpdateCache && $wxMplistSer->getValidMpList(true);
        //注册微信支付单例
        $payMpList = (new WxMpPayListService())->getValidMpList();
        if (!empty($payMpList)){
            foreach ($payMpList as $config){
                $this->app->singleton("wechat.payment.{$config['appid']}", function ($laravelApp) use ($config) {
                    //格式化配置
                    $formatConfig = [
                        'app_id' => $config['appid'] ?? '',
                        'mch_id' => $config['mch_id'] ?? '',
                        'key' => $config['key'] ?? '',
                        'cert_path' => !empty($config['cert_path']) ? storage_path('certificate/'.$config['cert_path']) : '',
                        'key_path' => !empty($config['key_path']) ? storage_path('certificate/'.$config['key_path']) : '',
                        'notify_url' => route('callback.payment.notify', ['appid'=>$config['appid']]),
                        'log' => [
                            'default' => env('WECHAT_LOG_ENV', 'develop'), // 默认使用的 channel，生产环境可以改为下面的 production
                            'channels' => [
                                // 测试环境
                                'develop' => [
                                    'driver' => 'daily',
                                    'path' => storage_path('logs/wechat_payment_'.$config['appid'].'.log'),
                                    'level' => 'debug',
                                ],
                                // 生产环境
                                'production' => [
                                    'driver' => 'daily',
                                    'path' => storage_path('logs/wechat_payment_'.$config['appid'].'.log'),
                                    'level' => 'info',
                                ],
                            ],
                        ],
                    ];
                    $finalConfig = array_merge(config('wechat.defaults', []), ['http' => config('wechat.http', [])], $formatConfig);
                    $app = new Payment($finalConfig);
                    //是否使用laravel自带缓存
                    if (config('wechat.defaults.use_laravel_cache')) {
                        $app['cache'] = $laravelApp['cache.store'];
                    }
                    $app['request'] = $laravelApp['request'];

                    return $app;
                });
                if ($config['is_default']){
                    $this->app->alias("wechat.payment.".$config['appid'], 'wechat.payment');
                }
            }
        }
    }
}
